package controller

import (
	"a-admin/web/domain"
	"a-common/utils"
	"fmt"
	"strconv"
	"sync"
	"time"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/websocket/v2"
)

var (
	rtcWsControllerTemp *RtcWsController
	rtcWsControllerOnce sync.Once

	textMessage   = 1  // TextMessage denotes a text data message.
	binaryMessage = 2  // BinaryMessage denotes a binary data message.
	closeMessage  = 8  // CloseMessage denotes a close control message.
	pingMessage   = 9  // PingMessage denotes a ping control message.
	pongMessage   = 10 // PongMessage denotes a pong control message.
)

// 定义一个空结构体
type EmptyStruct struct{}

type RtcWsController struct {
	online int64
	WsMap  sync.Map
}

func NewRtcWsController() *RtcWsController {
	rtcWsControllerOnce.Do(func() {
		rtcWsControllerTemp = &RtcWsController{}
	})
	return rtcWsControllerTemp
}

// WsHandler WS通讯
func (m *RtcWsController) WsHandler(c *websocket.Conn) {
	uid := c.Query("id")
	if uid == "" {
		return
	}
	sessionId := utils.NewIdUtils().GetNanoId()
	if sessionId == "" {
		return
	}
	var ws domain.WsClient
	ws.Create(uid)
	m.online++
	fmt.Printf("New ws Session=%s, UserId=%s, onLine=%d \n", sessionId, ws.GetUserId(), m.online)

	m.WsMap.Store(sessionId, &ws)
	wDone := make(chan struct{})
	rDone := make(chan struct{})
	defer func() {
		m.online--
		wDone <- struct{}{} // 结束写
		m.WsMap.Delete(sessionId)
		fmt.Printf("Lost ws Session=%s, UserId=%s, onLine=%d \n", sessionId, ws.GetUserId(), m.online)
	}()

	// 创建写协程
	go handlerWrite(c, &ws, &rDone, &wDone)

	// 一直读
	for {
		select {
		case <-rDone:
			return
		default:
			mt, msg, err := c.ReadMessage()
			if err != nil {
				fmt.Println("read err:", err)
				return
			}
			// 判断是否是心跳消息
			if mt == pingMessage || string(msg) == "ping" {
				// 响应
				err := c.WriteMessage(pongMessage, []byte("pong"))
				if err != nil {
					fmt.Println("pong err:", err)
					return
				}
			}
			// 正常消息，需要判断消息类型，是文本消息还是二进制消息
			if mt == textMessage {
				fmt.Printf("recv[text:%d]: %s \n", mt, msg)
			} else if mt == binaryMessage {
				fmt.Printf("recv[binary:%d]: %s \n", mt, msg)
			} else if mt == closeMessage {
				fmt.Printf("recv[close:%d]: %s \n", mt, msg)
			} else {
				fmt.Printf("recv[unknow:%d]: %s \n", mt, msg)
			}
		}
	}
}

// handlerWrite 处理写
func handlerWrite(c *websocket.Conn, ws *domain.WsClient, rDone, wDone *chan struct{}) {
	// 创建一个定时器
	ticker := time.NewTicker(30 * time.Second)
	defer func() {
		ticker.Stop()
		*rDone <- struct{}{} // 结束读
	}()
	for {
		select {
		case <-*wDone: // 结束信号
			return
		case <-ticker.C: // 心跳消息
			err := c.WriteMessage(textMessage, []byte("ping"))
			if err != nil {
				return
			}
		case w, ok := <-ws.GetTextChan(): // 正常消息
			if !ok {
				return
			} else {
				// fmt.Printf("recv: %s", w)
				err := c.WriteMessage(textMessage, w)
				if err != nil {
					fmt.Println("write err:", err)
					return
				}
			}
		case w, ok := <-ws.GetBinaryChan():
			if !ok {
				return
			} else {
				err := c.WriteMessage(textMessage, w)
				if err != nil {
					fmt.Println("write err:", err)
					return
				}
			}
		case w, ok := <-ws.GetCloseChan():
			if !ok {
				return
			} else {
				err := c.WriteMessage(textMessage, w)
				if err != nil {
					fmt.Println("write err:", err)
					return
				}
			}
		}
	}
}

// SendTestMsg 发送测试消息
func (m *RtcWsController) SendTestMsg(c *fiber.Ctx) error {
	cId := c.Params("userid")
	msg := c.Params("msg")
	i := m.SendWsMsg(cId, []byte(msg+"\n"))
	return c.SendString("消息已投递:" + strconv.FormatInt(i, 10))
}

func (m *RtcWsController) SendWsMsg(clientId string, msg []byte) int64 {
	var i int64
	m.WsMap.Range(func(key, value any) bool {
		_, ok := key.(string)
		if !ok {
			return true
		}
		v, ok := value.(*domain.WsClient)
		if !ok {
			return true
		}
		if clientId == "0" {
			// 广播
			v.GetTextChan() <- msg
			i++
		} else {
			// p2p
			if v.GetUserId() == clientId {
				v.GetTextChan() <- msg
				i++
			}
		}
		return true
	})
	return i
}
